import {defineComponent, h, ref, PropType, resolveComponent, watchEffect, computed} from 'vue';

import {renderLabel, renderIcon} from './helper.ts';
import {resolveOptions, getTypesValueByPath, getMenusByTypesValue} from './helper.ts';

export default defineComponent({
  name: 'FxMenus',
  inheritAttrs: false,
  props: {
    layout: {
      type: String as PropType<'side' | 'top' | 'combine' | 'mixture'>,
      default: 'side'
    },
    typeWidth: {
      type: Number as PropType<number>,
      default: 90
    },
    collapsed: {
      type: Boolean as PropType<boolean>,
      default: false
    },
    options: {
      type: Array as PropType<object[]>,
      default: () => {
        return [];
      }
    },
    mode: {
      type: String as PropType<string>,
    },
    value: {
      type: String as PropType<string>,
    },
    first: {
      type: Boolean as PropType<boolean>,
      default: false
    },
    keyField: {
      type: String as PropType<string>,
      default: 'path'
    },
    labelField: {
      type: String as PropType<string>,
      default: 'name'
    },
    renderLabel: {
      type: Function,
    },
    renderIcon: {
      type: Function,
    },
    mixtureBordered: {
      type: Boolean as PropType<boolean>,
      default: true
    }
  },
  emits: [],
  setup: function (props, context) {
    const menuOptionsRef = ref(resolveOptions(props.first));
    const typesRef = computed(() => menuOptionsRef.value.types);
    const typesValueRef = computed(() => getTypesValueByPath(menuOptionsRef.value, props.value));
    const menusRef = computed(() => getMenusByTypesValue(menuOptionsRef.value, typesValueRef.value));
    const mixtureTypesRef = computed(() => props.collapsed ? props.options : typesRef.value);
    const mixtureTypesValueRef = computed(() => props.collapsed ? props.value : typesValueRef.value);

    const renderSide = () => {
      return h(resolveComponent('NLayout'), {
        class: 'fx-menus-layout',
        style: 'height:100%;',
        hasSider: true
      }, {
        default: () => [
          h(resolveComponent('NLayoutContent'), {
            nativeScrollbar: false,
          }, {
            default: () => h(resolveComponent('NMenu'), {
              class: 'fx-menus-side__menus',
              ...context.attrs,
              mode: 'vertical',
              value: props.value,
              options: props.options,
              collapsed: props.collapsed,
              keyField: props.keyField,
              labelField: props.labelField,
              renderLabel: props.renderLabel || renderLabel,
              renderIcon: props.renderIcon || renderIcon
            })
          })
        ]
      });
    };

    const renderTop = () => {
      return h(resolveComponent('NMenu'), {
        class: 'fx-menus-top__menus',
        mode: 'horizontal',
        value: props.value,
        options: props.options,
        collapsed: props.collapsed,
        keyField: props.keyField,
        labelField: props.labelField,
        renderLabel: props.renderLabel || renderLabel,
        renderIcon: props.renderIcon || renderIcon
      });
    };

    const renderCombine = () => {
      const mode = props.mode;
      if ('horizontal' === mode) {
        return h(resolveComponent('NMenu'), {
          class: 'fx-menus-combine__types',
          mode: 'horizontal',
          value: typesValueRef.value,
          options: typesRef.value,
          collapsedWidth: props.typeWidth,
          keyField: props.keyField,
          labelField: props.labelField,
          renderLabel: props.renderLabel || renderLabel,
          renderIcon: props.renderIcon || renderIcon,
          responsive: true
        });
      }
      return h(resolveComponent('NLayout'), {
        class: 'fx-menus-layout',
        style: 'height:100%;',
        hasSider: true
      }, {
        default: () => [
          h(resolveComponent('NLayoutContent'), {
            nativeScrollbar: false,
          }, {
            default: () => h(resolveComponent('NMenu'), {
              class: 'fx-menus-combine__menus',
              ...context.attrs,
              mode: 'vertical',
              value: props.value,
              options: menusRef.value,
              collapsed: props.collapsed,
              keyField: props.keyField,
              labelField: props.labelField,
              renderLabel: props.renderLabel || renderLabel,
              renderIcon: props.renderIcon || renderIcon
            })
          })
        ]
      });
    };

    const renderMixture = () => {
      return h(resolveComponent('NLayout'), {
        class: 'fx-menus-layout',
        style: 'height:100%;',
        hasSider: true
      }, {
        default: () => [
          h(resolveComponent('NLayoutSider'), {
            width: props.typeWidth,
            nativeScrollbar: false,
            bordered: !props.collapsed && props.mixtureBordered
          }, {
            default: () => h(resolveComponent('NMenu'), {
              class: 'fx-menus-mixture__types',
              mode: 'vertical',
              collapsed: true,
              value: mixtureTypesValueRef.value,
              options: mixtureTypesRef.value,
              collapsedWidth: 0,
              collapsedIconSize: 20,
              keyField: props.keyField,
              labelField: props.labelField,
              renderLabel: props.renderLabel || renderLabel,
              renderIcon: props.renderIcon || renderIcon
            })
          }),
          h(resolveComponent('NLayoutContent'), {
            nativeScrollbar: false,
          }, {
            default: () => h(resolveComponent('NMenu'), {
              class: 'fx-menus-mixture__menus',
              ...context.attrs,
              mode: 'vertical',
              value: props.value,
              options: menusRef.value,
              collapsed: props.collapsed,
              keyField: props.keyField,
              labelField: props.labelField,
              renderLabel: props.renderLabel || renderLabel,
              renderIcon: props.renderIcon || renderIcon
            })
          })
        ]
      });
    };

    watchEffect(() => {
      menuOptionsRef.value = resolveOptions(props.first, props.options);
    });

    return () => {
      return props.layout === 'top' ? renderTop()
        : props.layout === 'combine' ? renderCombine() :
          props.layout === 'mixture' ? renderMixture() : renderSide();
    };
  }
});